/*
 * Copyright (c) 2013-2015 Charkey. All rights reserved.
 *
 * This software is the confidential and proprietary information of Charkey.
 * You shall not disclose such Confidential Information and shall use it only
 * in accordance with the terms of the agreements you entered into with Charkey.
 *
 * Charkey MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
 *
 * Charkey SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
 * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

package cn.simastudio.talos.core.aop.aspect;

import cn.simastudio.talos.common.constants.SimaConstants;
import cn.simastudio.talos.common.utils.agent.BrowserInfoUtils;
import cn.simastudio.talos.common.utils.agent.OSInfoUtils;
import cn.simastudio.talos.common.utils.agent.RequestUtils;
import cn.simastudio.talos.core.aop.annotation.Logging;
import cn.simastudio.talos.core.service.base.LoggingService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * Usage: 日志Aspect
 *
 * @author Charkey
 * @date 2015/7/16 19:22
 */
@Aspect
@Order(2)
@Component
public class LoggingAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoggingAspect.class);

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private LoggingService loggingService;

    private static String getAnnotationDescription(JoinPoint joinPoint) throws Exception {
        // 获得JoinPoint处类名
        String targetName = joinPoint.getTarget().getClass().getName();
        // 获得JoinPoint处方法名
        String methodName = joinPoint.getSignature().getName();
        // 获得JoinPoint处参数
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazz = method.getParameterTypes();
                if (clazz.length == arguments.length) {
                    description = method.getAnnotation(Logging.class).description();
                    break;
                }
            }
        }
        return description;
    }

    @AfterReturning("@annotation(cn.simastudio.talos.core.aop.annotation.Logging)")
    public void afterReturning(JoinPoint joinPoint) throws Throwable {
        LOGGER.debug("After returning, normal method execution.");
        cn.simastudio.talos.core.model.base.Logging logging = new cn.simastudio.talos.core.model.base.Logging();
        logging.setClazz(joinPoint.getTarget().getClass().getName());
        logging.setMethod(joinPoint.getSignature().getName());
        logging.setDescription(getAnnotationDescription(joinPoint));
        String params = "";
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {
            for (Object arg : args) {
                params += arg + ";";
            }
        }
        logging.setParamSize(joinPoint.getArgs().length);
        logging.setParams(params);
        String currentUsername = String.valueOf(request.getSession().getAttribute(SimaConstants.System.CURRENT_USERNAME));
        String apiConsumer = String.valueOf(request.getSession().getAttribute(SimaConstants.System.API_CONSUMER));
        logging.setUsername((currentUsername != null && !currentUsername.equals("")) ? currentUsername : apiConsumer);
        String IP = RequestUtils.getRemoteAddress(request);
        logging.setIp(IP);
        // 耗时处理，需要优化
        //String IPInfo = RequestUtils.getIPInfo(IP);
        //logging.setIpInfo(IPInfo);
        logging.setUserAgent(request.getHeader("user-agent"));
        logging.setBrowser(BrowserInfoUtils.getBrowserInfo(request));
        logging.setOsInfo(OSInfoUtils.getOperateSystemInfo(request));
        logging.setCreateTime(new Date());
        logging.setOpFlag(1);
        loggingService.logging(logging);
    }

    @AfterThrowing("@annotation(cn.simastudio.talos.core.aop.annotation.Logging)")
    public void afterThrowing(JoinPoint joinPoint) throws Throwable {
        LOGGER.debug("After throwing, exception method execution.");
        cn.simastudio.talos.core.model.base.Logging logging = new cn.simastudio.talos.core.model.base.Logging();
        logging.setClazz(joinPoint.getTarget().getClass().getName());
        logging.setMethod(joinPoint.getSignature().getName());
        logging.setDescription(getAnnotationDescription(joinPoint));
        String params = "";
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {
            for (Object arg : args) {
                params += arg + ";";
            }
        }
        logging.setParamSize(joinPoint.getArgs().length);
        logging.setParams(params);
        String currentUsername = String.valueOf(request.getSession().getAttribute(SimaConstants.System.CURRENT_USERNAME));
        String apiConsumer = String.valueOf(request.getSession().getAttribute(SimaConstants.System.API_CONSUMER));
        logging.setUsername((currentUsername != null && !currentUsername.equals("")) ? currentUsername : apiConsumer);
        String IP = RequestUtils.getRemoteAddress(request);
        logging.setIp(IP);
        // 耗时处理，需要优化
        //String IPInfo = RequestUtils.getIPInfo(IP);
        //logging.setIpInfo(IPInfo);
        logging.setUserAgent(request.getHeader("user-agent"));
        logging.setBrowser(BrowserInfoUtils.getBrowserInfo(request));
        logging.setOsInfo(OSInfoUtils.getOperateSystemInfo(request));
        logging.setCreateTime(new Date());
        logging.setOpFlag(1);
        loggingService.logging(logging);
    }
}
